package com.healtyprj.rsa;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

import org.apache.commons.codec.binary.Base64;

public class Main {
	private static final String CIPHER_ALGORITHM = "RSA";
	private static final String CIPHER_MODE = CIPHER_ALGORITHM + "/ECB/PKCS1PADDING";

	private static final String PRIVATE_KEY_FILE = "pkey.pk8";
	private static final String PUBLIC_KEY_FILE  = "publicKey.der";

	public static void main(String[] args) {
		Main app = new Main();

		InputStreamReader input = new InputStreamReader(System.in);
		BufferedReader reader = new BufferedReader(input, 1);
		for (;;) {
			System.out.print("INPUT:     ");
			System.out.flush();

			String line;
			try {
				line = reader.readLine();
				if (line == null) break;
			} catch (IOException e) {
				e.printStackTrace();
				break;
			}

			byte[] encrypted = app.encryptWithPrivateKey(line.getBytes());
			System.out.print("ENCRYPTED: ");
			System.out.println(Base64.encodeBase64(encrypted));

			byte[] decrypted = app.decryptWithPublicKey(encrypted);
			System.out.print("DECRYPTED: ");
			System.out.println(new String(decrypted));

			System.out.println();
		}
	}

	private Cipher cipher;
	private Key secret_key;
	private Key public_key;

	public Main() {
		try {
			cipher = Cipher.getInstance(CIPHER_MODE);


			KeyFactory keyfactory = KeyFactory.getInstance(CIPHER_ALGORITHM);
			KeySpec keyspec;

			keyspec = new PKCS8EncodedKeySpec(loadBinaryFile(PRIVATE_KEY_FILE));
			secret_key = keyfactory.generatePrivate(keyspec);

			keyspec = new X509EncodedKeySpec(loadBinaryFile(PUBLIC_KEY_FILE));
			public_key = keyfactory.generatePublic(keyspec);
		} catch (GeneralSecurityException e) {
			throw new RuntimeException(e);
		}
	}

	public byte[] encryptWithPrivateKey(byte[] source) {
		try {
			cipher.init(Cipher.ENCRYPT_MODE, secret_key);
			return cipher.doFinal(source);
		} catch (GeneralSecurityException e) {
			throw new RuntimeException(e);
		}
	}

	public byte[] decryptWithPublicKey(byte[] source) {
		try {
			cipher.init(Cipher.DECRYPT_MODE, public_key);
			return cipher.doFinal(source);
		} catch (GeneralSecurityException e) {
			throw new RuntimeException(e);
		}
	}

	private static byte[] loadBinaryFile(String filename) {
		try {
			FileInputStream in = new FileInputStream(filename);
			byte[] data = new byte[in.available()];
			in.read(data);
			in.close();
			return data;
		} catch (IOException e) {
			e.printStackTrace();
		}

		return new byte[0];
	}
}